import React, { FC, memo, ReactNode, useEffect, useState } from 'react'
import { FormInstance, Input, Tree, TreeProps } from 'antd'
import { myShallowEqual, useMySelector } from '@/store'
import { ActionDesc } from '@/global/constant'
import confirmModal from '@/utils/confirm-modal'
import {
  fetchPageAddOrEditAction,
  fetchPageDeleteAction
} from '@/store/module/main/page-common'
import { fetchAssignTreeListAction } from '@/store/module/main/role-list'
import usePageSearch from '@/hooks/use-page-search'
import usePageModal from '@/hooks/use-page-modal'
import PageSearch from '@/components/page-search'
import PageContent from '@/components/page-content'
import PageModal from '@/components/page-modal'
import VerifyCodeButton from '@/components/verify-code-button'
import roleListSearch from './config/rolelist-search'
import roleListContent from './config/rolelist-content'
import roleListModalAssignPermission from './config/roleist-modal-assign-permission'
import getRoleListModalAddOrEdit from './config/rolelist-modal-add-or-edit'
import { reqAssignPermission } from '@/service/module/main/system/role-list'
import usePageContent from '@/hooks/use-page-content'

interface IProps {
  children?: ReactNode
}

const inputWithVerifyCodeStyle = {
  display: 'flex',
  alignItems: 'center'
}

// 获取菜单中所有父级菜单的id
function filterMenuParentIds(menuList: any[]) {
  const ids: string[] = []
  menuList.forEach((item) => {
    if (item.children && item.children.length) {
      ids.push(item.menuId, ...filterMenuParentIds(item.children))
    }
  })
  return ids
}

const treeFieldNames = {
  key: 'menuId',
  title: 'menuLabel'
}

const RoleList: FC<IProps> = (props) => {
  // 从 Redux store 中获取数据，使用 myShallowEqual 函数来优化性能
  const { userInfo, menuList } = useMySelector(
    (state) => ({
      userInfo: state.app.userInfo,
      menuList: state.roleList.assignTreeList.menuList
    }),
    myShallowEqual
  )

  // 使用 usePageSearch、usePageModal 和 usePageContent 自定义 Hook 并提取返回值和函数
  const { pageContentRef, searchClick, resetClick } = usePageSearch()
  const { pageModalRef, onModalOk, onModalCancel, getCodeClick } = usePageModal(
    {
      okCb,
      afterCloseResetStatusCb,
      cancelCb
    }
  )
  const {
    modal: [curModalConfig, setCurModalConfig],
    record: [currentRecord, setCurrentRecord],
    dispatch,
    toSecondAuth,
    handleSecondAuth
  } = usePageContent({ pageModalRef })

  // 定义一个状态 treeCheckedKeys 和用于更新该状态的函数 setTreeCheckedKeys
  const [treeCheckedKeys, setTreeCheckedKeys] = useState<string[]>([])

  // 用于处理模态框的确认事件的回调函数
  async function okCb(form: FormInstance | undefined) {
    // 获取当前配置的信息，看一下是属于什么类型的表单描述
    const { desc } = curModalConfig.formProps

    // 获取表单数据
    const values = form?.getFieldsValue()

    if (desc === ActionDesc.SecondAuth) {
      /** 1、当前描述为：二次认证 **/
      return toSecondAuth(values)
    } else if (desc === ActionDesc.Add) {
      /** 2、当前描述为：角色新增 **/
      return await roleToAddOrEdit(values, true)
    } else if (desc === ActionDesc.Edit) {
      /** 3、当前描述为：角色编辑 **/
      return await roleToAddOrEdit(values, false)
    } else if (desc === ActionDesc.RoleAssignPermission) {
      /** 4、当前描述为：权限分配 **/
      return await roleToAssignPermission()
    }
  }

  // 用于重置模态框状态的回调函数
  function afterCloseResetStatusCb() {
    // 这一步非常关键：每次点击确认后，要销毁该 modal 框的状态，
    // 但是只有 modal 的配置发生改变才会重新渲染这个 modal 组件，
    // 所以这里改为空。假如我们两次点击二次认证框，但是希望下一次进去消除上一次残留的状态，
    // 就要让它的配置发生改变。
    setCurModalConfig({})
  }

  // 用于处理模态框的取消事件的回调函数
  function cancelCb() {
    setCurModalConfig({})
  }

  // 通用：按钮的操作---这里能进行任意按钮的操作
  async function actionClick(actionType: any, record?: any) {
    // 设置当前行数据：如果是批量操作和新增就没有record也要设置，表明是空状态
    setCurrentRecord(record)
    // 操作类型
    if (actionType === ActionDesc.Add) {
      /** 新增 **/
      const config = getRoleListModalAddOrEdit(true)
      setCurModalConfig(config)
      pageModalRef.current?.openModal()
    } else if (actionType === ActionDesc.Edit) {
      /**  编辑  **/
      const config = getRoleListModalAddOrEdit(false)
      setCurModalConfig(config)
      pageModalRef.current?.openModal()
    } else if (actionType === ActionDesc.Delete) {
      /** 删除 **/
      handleSecondAuth(() => {
        confirmModal('是否删除该角色?').then(() =>
          dispatch(fetchPageDeleteAction(record.roleId))
        )
      })
    } else if (actionType === ActionDesc.RoleAssignPermission) {
      /** 分配权限 **/
      roleToAssignPermissionBeforeOpen(record)
    }
  }

  // 通用：处理“编辑”的回显数据的，只要config一改变，就手动设置初始值
  useEffect(() => {
    if (curModalConfig?.formProps?.desc === ActionDesc.Edit) {
      const { remark, roleName } = currentRecord
      // 整理表单参数
      const form = pageModalRef.current?.getFormInstance()
      form?.setFieldsValue({
        remark,
        roleName
      })
    }
  }, [curModalConfig])

  // 新增或者修改， 参数2：true -> 新增
  async function roleToAddOrEdit(values: any, isAdd: boolean) {
    const newParams = {
      ...values,
      ...(currentRecord?.roleId !== undefined && {
        roleId: currentRecord.roleId
      })
    }
    return dispatch(
      fetchPageAddOrEditAction({
        params: newParams,
        isAdd,
        isNeedEncrypt: false
      })
    )
  }

  // 分配权限框---打开前
  function roleToAssignPermissionBeforeOpen(record: any) {
    const params = {
      roleId: record.roleId,
      userId: userInfo.userId
    }
    // 获取操作目标角色的选择树节点和所有权限
    dispatch(fetchAssignTreeListAction(params)).then(({ payload }) => {
      const { menuList, checkList } = payload
      const ids = filterMenuParentIds(menuList)
      // 获取选中的子菜单id
      const result = checkList.filter((item: string) => !ids.includes(item))
      setTreeCheckedKeys(result)
      // 更改modal配置并打开窗口
      setCurModalConfig(roleListModalAssignPermission)
      pageModalRef.current?.openModal()
    })
  }

  // 分配权限--打开后
  async function roleToAssignPermission() {
    const data = {
      selectMenuList: treeCheckedKeys,
      roleId: currentRecord.roleId
    }
    return await reqAssignPermission(data)
  }

  // 选中树形数据发生改变时
  const onCheck: TreeProps['onCheck'] = (checkedKeys: any) => {
    setTreeCheckedKeys(checkedKeys)
  }

  return (
    <>
      <PageSearch
        config={roleListSearch}
        searchClick={searchClick}
        resetClick={resetClick}
      />
      <PageContent
        ref={pageContentRef}
        config={roleListContent}
        actionClick={actionClick}
      />
      <PageModal
        ref={pageModalRef}
        modalConfig={curModalConfig}
        onOk={onModalOk}
        onCancel={onModalCancel}
      >
        <div key="code" style={inputWithVerifyCodeStyle}>
          <Input name="code" />
          <VerifyCodeButton onClick={getCodeClick} />
        </div>
        <Tree
          key="tree"
          fieldNames={treeFieldNames}
          checkable
          onCheck={onCheck}
          checkedKeys={treeCheckedKeys}
          treeData={menuList}
        />
      </PageModal>
    </>
  )
}

export default memo(RoleList)
